from docx import Document
from docx.shared import Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from typing import Dict, Optional, Any
from docx.text.paragraph import Paragraph
from docx.text.run import Run

class WordStyleSystem:
    """Word样式系统，处理所有可能的样式情况"""
    
    def __init__(self, doc: Document):
        """初始化样式系统"""
        self.doc = doc
        self.style_map: Dict[str, Dict[str, Any]] = {}  # 样式映射表
        self.style_hierarchy: Dict[str, str] = {}  # 样式继承关系
        self.default_styles = {
            'paragraph': ['Normal', 'Body Text'],
            'heading': ['Heading 1', 'Heading 2', 'Heading 3'],
            'list': ['List Paragraph', 'List Bullet', 'List Number'],
            'table': ['Table Normal', 'Table Grid'],
            'character': ['Default Paragraph Font', 'Emphasis', 'Strong']
        }
        
        # 初始化样式系统
        self._initialize_styles()
        
        # 创建样式名称映射
        self.style_name_map = {}
        for style_name in self.style_map.keys():
            # 创建不同变体的映射
            self._add_style_name_variants(style_name, style_name)
            # 处理 Web 后缀
            if style_name.lower().startswith('normal'):
                self._add_style_name_variants('Normal (Web)', style_name)
            elif style_name.lower().startswith('heading'):
                self._add_style_name_variants(f'{style_name} (Web)', style_name)
            elif style_name.lower().startswith('default paragraph font'):
                self._add_style_name_variants('Default Paragraph Font (Web)', style_name)

    def _add_style_name_variants(self, base_name: str, target_name: str):
        """添加样式名称的变体到映射中"""
        # 添加原始名称
        self.style_name_map[base_name.lower()] = target_name
        
        # 添加去除空格的变体
        no_space = base_name.replace(' ', '').lower()
        if no_space != base_name.lower():
            self.style_name_map[no_space] = target_name
        
        # 添加去除括号的变体
        no_parentheses = base_name.replace('(', '').replace(')', '').lower()
        if no_parentheses != base_name.lower():
            self.style_name_map[no_parentheses] = target_name
            
        # 添加小写变体
        lowercase = base_name.lower()
        if lowercase != base_name:
            self.style_name_map[lowercase] = target_name

    def _get_normalized_style_name(self, style_name: str) -> Optional[str]:
        """获取规范化后的样式名称"""
        # 尝试找到匹配的样式名称
        normalized_name = self.style_name_map.get(style_name.lower())
        if normalized_name:
            return normalized_name
            
        # 如果找不到，尝试去除 Web 后缀
        if style_name.lower().endswith(' (web)'):
            base_name = style_name[:-6].strip()
            normalized_name = self.style_name_map.get(base_name.lower())
            if normalized_name:
                return normalized_name
        
        # 如果还是找不到，返回原始名称
        return style_name
        
    def _initialize_styles(self):
        """初始化样式系统"""
        # 1. 获取所有样式
        for style in self.doc.styles:
            self.style_map[style.name] = {
                'type': style.type,
                'base_style': style.base_style.name if style.base_style else None,
                'properties': self._get_style_properties(style)
            }
            
            # 2. 构建样式继承关系
            if style.base_style:
                self.style_hierarchy[style.name] = style.base_style.name
        
        # 3. 添加默认样式映射
        for category, styles in self.default_styles.items():
            for style_name in styles:
                if style_name not in self.style_map:
                    self.style_map[style_name] = {
                        'type': category,
                        'base_style': None,
                        'properties': self._get_default_properties(category)
                    }
    
    def _get_style_properties(self, style) -> Dict[str, Any]:
        """获取样式的所有属性，确保完全匹配样本文档"""
        props = {
            'font': {
                'name': style.font.name,
                'size': style.font.size,
                'bold': style.font.bold,
                'italic': style.font.italic,
                'underline': style.font.underline,
                'color': style.font.color.rgb if style.font.color else None,
                'highlight': style.font.highlight_color,
                'all_caps': style.font.all_caps,
                'small_caps': style.font.small_caps,
                'strike': style.font.strike,
                'double_strike': style.font.double_strike,
                'shadow': style.font.shadow,
                'outline': style.font.outline,
                'emboss': style.font.emboss,
                'imprint': style.font.imprint
            }
        }
        
        # 根据样式类型添加相应的属性
        if style.type == 'paragraph':
            props['paragraph_format'] = {
                'alignment': style.paragraph_format.alignment,
                'space_before': style.paragraph_format.space_before,
                'space_after': style.paragraph_format.space_after,
                'line_spacing': style.paragraph_format.line_spacing,
                'line_spacing_rule': style.paragraph_format.line_spacing_rule,
                'first_line_indent': style.paragraph_format.first_line_indent,
                'left_indent': style.paragraph_format.left_indent,
                'right_indent': style.paragraph_format.right_indent,
                'keep_together': style.paragraph_format.keep_together,
                'keep_with_next': style.paragraph_format.keep_with_next,
                'page_break_before': style.paragraph_format.page_break_before,
                'widow_control': style.paragraph_format.widow_control,
                'tab_stops': [],
                'list_level': None,  # 列表级别
                'list_style': None,  # 列表样式
                'list_indent': None  # 列表缩进
            }
            
            # 处理制表位
            for tab in style.paragraph_format.tab_stops:
                props['paragraph_format']['tab_stops'].append({
                    'position': tab.position,
                    'alignment': tab.alignment,
                    'leader': tab.leader
                })
            
            # 处理列表格式
            if hasattr(style.paragraph_format, '_element'):
                # 获取列表级别
                numPr = style.paragraph_format._element.xpath('w:numPr')
                if numPr:
                    ilvl = numPr[0].xpath('w:ilvl')
                    if ilvl:
                        props['paragraph_format']['list_level'] = int(ilvl[0].get('{http://schemas.openxmlformats.org/wordprocessingml/2006/main}val'))
                    
                    # 获取列表样式
                    numId = numPr[0].xpath('w:numId')
                    if numId:
                        props['paragraph_format']['list_style'] = int(numId[0].get('{http://schemas.openxmlformats.org/wordprocessingml/2006/main}val'))
                    
                    # 计算列表缩进
                    if props['paragraph_format']['list_level'] is not None:
                        # 每个级别增加缩进，单位为磅
                        indent_per_level = 36  # 通常Word的缩进单位
                        props['paragraph_format']['list_indent'] = props['paragraph_format']['list_level'] * indent_per_level
                        props['paragraph_format']['left_indent'] = props['paragraph_format']['list_indent']
            
            # 处理特殊缩进情况
            if style.paragraph_format.first_line_indent:
                # 如果是悬挂缩进（负值）
                if style.paragraph_format.first_line_indent < 0:
                    props['paragraph_format']['hanging_indent'] = style.paragraph_format.first_line_indent
                    props['paragraph_format']['first_line_indent'] = 0
                # 如果是首行缩进（正值）
                else:
                    props['paragraph_format']['hanging_indent'] = 0
            else:
                props['paragraph_format']['hanging_indent'] = 0
        
        # 处理字符样式属性
        if style.type == 'character':
            props['run_properties'] = {
                'bold': style.font.bold,
                'italic': style.font.italic,
                'underline': style.font.underline,
                'color': style.font.color.rgb if style.font.color else None,
                'highlight': style.font.highlight_color,
                'all_caps': style.font.all_caps,
                'small_caps': style.font.small_caps,
                'strike': style.font.strike,
                'double_strike': style.font.double_strike,
                'shadow': style.font.shadow,
                'outline': style.font.outline,
                'emboss': style.font.emboss,
                'imprint': style.font.imprint
            }
        
        return props
    
    def _get_default_properties(self, category: str) -> Dict[str, Any]:
        """获取默认样式属性"""
        return {
            'font': {
                'name': 'Calibri',
                'size': Pt(11),
                'bold': False,
                'italic': False,
                'underline': None,
                'color': RGBColor(0, 0, 0),
                'highlight': None
            },
            'paragraph_format': {
                'alignment': WD_ALIGN_PARAGRAPH.LEFT,
                'space_before': Pt(0),
                'space_after': Pt(8),
                'line_spacing': 1.0,
                'first_line_indent': Pt(0),
                'left_indent': Pt(0),
                'right_indent': Pt(0)
            },
            'run_properties': {
                'bold': False,
                'italic': False,
                'underline': None,
                'color': RGBColor(0, 0, 0)
            }
        }
    
    def apply_style(self, target: Any, style_name: str):
        """应用样式，考虑所有层级"""
        # 获取规范化后的样式名称
        normalized_style_name = self._get_normalized_style_name(style_name)
        
        # 如果仍然找不到样式，使用默认样式
        if normalized_style_name not in self.style_map:
            if style_name.lower().startswith('heading'):
                # 对于标题样式，使用 Heading 1 作为默认
                normalized_style_name = 'Heading 1'
            else:
                # 对于其他样式，使用 Normal 作为默认
                normalized_style_name = 'Normal'
            print(f"Warning: Style '{style_name}' not found, using '{normalized_style_name}' as fallback")
        
        # 1. 获取完整样式属性
        style_props = self._get_complete_style_properties(normalized_style_name)
        
        # 1. 获取完整样式属性
        style_props = self._get_complete_style_properties(style_name)
        
        # 2. 根据目标类型应用样式
        try:
            if isinstance(target, Paragraph):
                # 应用段落格式
                if 'paragraph_format' in style_props:
                    if hasattr(target.paragraph_format, 'alignment'):
                        target.paragraph_format.alignment = style_props['paragraph_format']['alignment']
                    if hasattr(target.paragraph_format, 'space_before'):
                        target.paragraph_format.space_before = style_props['paragraph_format']['space_before']
                    if hasattr(target.paragraph_format, 'space_after'):
                        target.paragraph_format.space_after = style_props['paragraph_format']['space_after']
                    if hasattr(target.paragraph_format, 'line_spacing'):
                        target.paragraph_format.line_spacing = style_props['paragraph_format']['line_spacing']
                    if hasattr(target.paragraph_format, 'first_line_indent'):
                        target.paragraph_format.first_line_indent = style_props['paragraph_format']['first_line_indent']
                    if hasattr(target.paragraph_format, 'left_indent'):
                        target.paragraph_format.left_indent = style_props['paragraph_format']['left_indent']
                    if hasattr(target.paragraph_format, 'right_indent'):
                        target.paragraph_format.right_indent = style_props['paragraph_format']['right_indent']
                
                # 应用字体属性（段落级）
                if hasattr(target.style.font, 'name'):
                    target.style.font.name = style_props['font']['name']
                if hasattr(target.style.font, 'size'):
                    target.style.font.size = style_props['font']['size']
                if hasattr(target.style.font, 'bold'):
                    target.style.font.bold = style_props['font']['bold']
                if hasattr(target.style.font, 'italic'):
                    target.style.font.italic = style_props['font']['italic']
                if hasattr(target.style.font, 'underline'):
                    target.style.font.underline = style_props['font']['underline']
                if hasattr(target.style.font, 'color') and style_props['font']['color']:
                    target.style.font.color.rgb = style_props['font']['color']
                if hasattr(target.style.font, 'highlight_color'):
                    target.style.font.highlight_color = style_props['font']['highlight']
            
            elif isinstance(target, Run):
                # 应用字体属性（文本运行级）
                if hasattr(target.font, 'name'):
                    target.font.name = style_props['font']['name']
                if hasattr(target.font, 'size'):
                    target.font.size = style_props['font']['size']
                if hasattr(target.font, 'bold'):
                    target.font.bold = style_props['font']['bold']
                if hasattr(target.font, 'italic'):
                    target.font.italic = style_props['font']['italic']
                if hasattr(target.font, 'underline'):
                    target.font.underline = style_props['font']['underline']
                if hasattr(target.font, 'color') and style_props['font']['color']:
                    target.font.color.rgb = style_props['font']['color']
                if hasattr(target.font, 'highlight_color'):
                    target.font.highlight_color = style_props['font']['highlight']
                
                # 应用文本运行属性
                if 'run_properties' in style_props:
                    if hasattr(target.font, 'bold'):
                        target.font.bold = style_props['run_properties']['bold']
                    if hasattr(target.font, 'italic'):
                        target.font.italic = style_props['run_properties']['italic']
                    if hasattr(target.font, 'underline'):
                        target.font.underline = style_props['run_properties']['underline']
                    if hasattr(target.font, 'color') and style_props['run_properties']['color']:
                        target.font.color.rgb = style_props['run_properties']['color']
        except Exception as e:
            print(f"Warning: Error applying style to {type(target).__name__}: {e}")
    
    def _get_complete_style_properties(self, style_name: str) -> Dict[str, Any]:
        """获取完整样式属性，包括继承的属性"""
        props = self.style_map[style_name]['properties'].copy()
        
        # 追溯继承链，合并所有属性
        current_style = style_name
        while current_style in self.style_hierarchy:
            base_style = self.style_hierarchy[current_style]
            base_props = self.style_map[base_style]['properties']
            
            # 根据样式类型合并属性
            if 'paragraph_format' in base_props and 'paragraph_format' not in props:
                props['paragraph_format'] = base_props['paragraph_format']
            if 'run_properties' in base_props and 'run_properties' not in props:
                props['run_properties'] = base_props['run_properties']
            
            # 合并字体属性
            if 'font' in base_props:
                for sub_key, value in base_props['font'].items():
                    if props['font'][sub_key] is None:
                        props['font'][sub_key] = value
            
            current_style = base_style
        
        return props
